"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

import sys
from django.db import models
from django.db.models import Max
from django.utils.translation import gettext_lazy as _
from siriuso.models.postgres import CallableEncoder
from siriuso.utils import default_lingvo, get_enhavo
from main.models import SiriusoBazaAbstrakta3
from main.models import SiriusoTipoAbstrakta
from main.models import Uzanto


# Функционал Здоровье
# Типы реализаций задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoTaskoRealigoTipo(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_taskoj_realigoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de realigoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de realigoj')


# Типы направлений задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoDirektoTipo(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_direktoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de direktoj de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de direktoj de taskoj de sano')


# Виды направлений задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoDirektoSpeco(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_direktoj_specoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Speco de direktoj de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Specoj de direktoj de taskoj de sano')


# Абстрактный класс направлений задач здоровья, использует абстрактный класс SiriusoBazaAbstrakta3
class SanoDirektoAbstrakta(SiriusoBazaAbstrakta3):

    # тип направления
    tipo = models.ForeignKey(SanoDirektoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # вид направлений
    speco = models.ForeignKey(SanoDirektoSpeco, verbose_name=_('Speco'), blank=False, default=None,
                              on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # указание что это абстрактный класс
        abstract = True

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле ID этой модели
        return '{}'.format(self.id)


# Типы этапов задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoEtapoTipo(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_etapoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de etapoj de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de etapoj de taskoj de sano')


# Виды этапов задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoEtapoSpeco(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_etapoj_specoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Speco de etapoj de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Specoj de etapoj de taskoj de sano')


# Абстрактный класс этапов задач здоровья, использует абстрактный класс SiriusoBazaAbstrakta3
class SanoEtapoAbstrakta(SiriusoBazaAbstrakta3):

    # тип этапа
    tipo = models.ForeignKey(SanoEtapoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # вид этапа
    speco = models.ForeignKey(SanoEtapoSpeco, verbose_name=_('Speco'), blank=False, default=None,
                              on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # указание что это абстрактный класс
        abstract = True

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле ID этой модели
        return '{}'.format(self.id)


# Типы задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoTaskoTipo(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # возможные типы реализации задачи
    tipo_realigo = models.ManyToManyField(SanoTaskoRealigoTipo, verbose_name=_('Tipo'), blank=False, default=None)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_taskoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de taskoj de sano')


# Виды задач здоровья, использует абстрактный класс SiriusoTipoAbstrakta
class SanoTaskoSpeco(SiriusoTipoAbstrakta):

    # название в таблице названий типов, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_taskoj_specoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Speco de taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Specoj de taskoj de sano')


# Абстрактный класс задач здоровья, использует абстрактный класс SiriusoBazaAbstrakta3
class SanoTaskoAbstrakta(SiriusoBazaAbstrakta3):

    # тип задачи
    tipo = models.ForeignKey(SanoTaskoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # вид задачи
    speco = models.ForeignKey(SanoTaskoSpeco, verbose_name=_('Speco'), blank=False, default=None,
                              on_delete=models.CASCADE)

    # если это подзадача, то какой задачи (рекурсивная связь)
    tasko = models.ForeignKey('self', verbose_name=_('Tasko'), blank=True, null=True,
                              related_name='%(app_label)s_%(class)s_tasko', on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # указание что это абстрактный класс
        abstract = True
        # читабельное название модели, в единственном числе

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле ID этой модели
        return '{}'.format(self.id)


# Глобальные задачи здоровья
# Шаблоны глобальных задач здоровья, использует абстрактный класс SiriusoBazaAbstrakta3
class SanoXeneralaTaskoWablono(SiriusoBazaAbstrakta3):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор шаблона глобальной задачи
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None, on_delete=models.CASCADE)

    # описание в таблице описаний задач, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_xeneralaj_taskoj_wablono'
        # читабельное название модели, в единственном числе
        verbose_name = _('Ŝablono de ĝeneralaj taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Ŝablonoj de ĝeneralaj taskoj de sano')

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(SanoXeneralaTaskoWablono, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                                   update_fields=update_fields)


# Направления глобальных задач здоровья, использует абстрактный класс SanoDirektoAbstrakta
class SanoXeneralaDirekto(SanoDirektoAbstrakta):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор направления глобальных задач
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None, on_delete=models.CASCADE)

    # описание в таблице описаний направлений, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_xeneralaj_direktoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Direkto de ĝeneralaj taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Direktoj de ĝeneralaj taskoj de sano')

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле priskribo этой модели
        return '{}'.format(get_enhavo(self.priskribo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(SanoXeneralaDirekto, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                              update_fields=update_fields)


# Этапы глобальных задач здоровья, использует абстрактный класс SanoEtapoAbstrakta
class SanoXeneralaEtapo(SanoEtapoAbstrakta):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # направление
    direkto = models.ForeignKey(SanoXeneralaDirekto, verbose_name=_('Direkto'), blank=False, default=None,
                                on_delete=models.CASCADE)

    # автор этапа глобальных задач
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None, on_delete=models.CASCADE)

    # описание в таблице описаний этапов, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_xeneralaj_etapoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Etapo de ĝeneralaj taskoj de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Etapoj de ĝeneralaj taskoj de sano')

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле priskribo этой модели
        return '{}'.format(get_enhavo(self.priskribo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(SanoXeneralaEtapo, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                            update_fields=update_fields)


# Глобальные задачи здоровья, использует абстрактный класс SanoTaskoAbstrakta
class SanoXeneralaTasko(SanoTaskoAbstrakta):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # этап
    etapo = models.ForeignKey(SanoXeneralaEtapo, verbose_name=_('Etapo'), blank=False, default=None,
                              on_delete=models.CASCADE)

    # автор глобальной задачи
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None, on_delete=models.CASCADE)

    # описание в таблице описаний задач, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_xeneralaj_taskoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Ĝenerala tasko de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Ĝeneralaj taskoj de sano')

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле ID этой модели
        return '{}'.format(self.id)

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(SanoXeneralaTasko, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                            update_fields=update_fields)


# Реализация глобальных задач здоровья, использует абстрактный класс SanoTaskoAbstrakta
class SanoXeneralaTaskoRealigo(SanoTaskoAbstrakta):

    # реализуемая задача
    tasko = models.ForeignKey(SanoXeneralaTasko, verbose_name=_('Tasko'), blank=False, default=None,
                              on_delete=models.CASCADE)

    # владелец реализации
    posedanto = models.ForeignKey(Uzanto, verbose_name=_('Posedanto'), blank=False, default=None,
                                  on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'sano_xeneralaj_taskoj_realigoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Realigo ĝeneralajn taskojn de sano')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Realigoj ĝeneralajn taskojn de sano')
